package woaini.fenger.core.task;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.spring.SpringUtil;
import java.util.*;
import lombok.AllArgsConstructor;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import woaini.fenger.core.base.boot.ApplicationStartupCompleted;
import woaini.fenger.core.task.anno.BotTask;
import woaini.fenger.core.task.vo.QuartzJobsVO;

/**
 * 机器人任务管理器
 *
 * @see woaini.fenger.core.task.BotTaskManager
 * @author yefeng {@code @Date} 2023-05-16 16:50:39
 */
@Component
@AllArgsConstructor
public class BotTaskManager implements ApplicationStartupCompleted {

  /**
   * @see Map<String, QuartzJobBean> 作业Bean映射
   */
  private static final Map<String, QuartzJobBean> JOB_BEAN_MAP = new HashMap<>();

  private Scheduler scheduler;

  @Override
  public void onInit() {

    Map<String, QuartzJobBean> beansOfType = SpringUtil.getBeansOfType(QuartzJobBean.class);
    for (QuartzJobBean quartzJobBean : beansOfType.values()) {
      BotTask botTask = AnnotationUtil.getAnnotation(quartzJobBean.getClass(), BotTask.class);
      if (botTask != null) {
        JOB_BEAN_MAP.put(botTask.name(), quartzJobBean);
      }
    }
  }

  /**
   * @MethodName createCornTask
   *
   * @param taskName 任务名称
   * @param nodeName 节点名称
   * @param cronExpression Cron表达式
   * @param description 描述
   * @param dataMap 数据地图
   * @author yefeng {@date 2024-01-31 10:35:04}
   * @since 1.0
   * @return boolean 创建corn任务
   */
  public boolean createCornTask(
      String taskName,
      String nodeName,
      String cronExpression,
      String description,
      Map<String, Object> dataMap) {
    try {
      if (MapUtil.isEmpty(dataMap)){
        dataMap = new HashMap<>(0);
      }
      QuartzJobBean classByCode = JOB_BEAN_MAP.get(nodeName);
      JobDataMap jobDataMap = new JobDataMap(dataMap);

      JobDetail jobDetail =
          JobBuilder.newJob(classByCode.getClass())
              .withIdentity(taskName, nodeName)
              .withDescription(description)
              .usingJobData(jobDataMap)
              .build();
      Trigger cornTrigger =
          TriggerBuilder.newTrigger()
              .withIdentity(taskName, nodeName)
              .withDescription(description)
              .startNow()
              .withSchedule(
                  CronScheduleBuilder.cronSchedule(cronExpression)
                      .withMisfireHandlingInstructionDoNothing())
              .build();
      scheduler.scheduleJob(jobDetail, cornTrigger);
    } catch (Exception e) {
      return false;
    }
    return true;
  }

  /**
   * @MethodName getAllJob
   *
   * @author yefeng {@date 2024-01-31 10:38:22}
   * @since 1.0
   * @return {@link List }<{@link QuartzJobsVO }> 获得所有工作
   */
  public List<QuartzJobsVO> getAllJob() {
    GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
    Set<JobKey> jobKeys = null;
    List<QuartzJobsVO> jobList = new ArrayList();
    try {
      jobKeys = scheduler.getJobKeys(matcher);
      for (JobKey jobKey : jobKeys) {
        List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
        for (Trigger trigger : triggers) {
          QuartzJobsVO job = new QuartzJobsVO();
          job.setJobDetailName(jobKey.getName());
          job.setGroupName(jobKey.getGroup());
          job.setJobCronExpression("触发器:" + trigger.getKey());
          Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
          job.setStatus(triggerState.name());
          if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;
            String cronExpression = cronTrigger.getCronExpression();
            job.setJobCronExpression(cronExpression);
            job.setDescription(cronTrigger.getDescription());
          }
          jobList.add(job);
        }
      }

    } catch (SchedulerException e) {
      e.printStackTrace();
    }
    return jobList;
  }

  /**
   * @MethodName deleteTask
   *
   * @param name 名字
   * @param group 组
   * @author yefeng {@date 2024-01-31 11:07:22}
   * @since 1.0
   * @return boolean 删除任务
   */
  public boolean deleteTask(String name, String group) {
    try {
      JobKey jobKey = JobKey.jobKey(name, group);
      TriggerKey triggerKey = TriggerKey.triggerKey(name, group);
      if (!scheduler.checkExists(jobKey)) {
        return true;
      }
      scheduler.pauseTrigger(triggerKey);
      scheduler.unscheduleJob(triggerKey);
      scheduler.deleteJob(jobKey);
      return true;
    } catch (SchedulerException e) {
      return false;
    }
  }

  /**
   * 暂停一个定时任务
   * @param name 名称
   * @param group 分组
   * @return 是否删除
   */
  public boolean pauseTask(String name, String group) {
    try {
      JobKey jobKey = JobKey.jobKey(name, group);
      if (!scheduler.checkExists(jobKey)) {
        return false;
      }
      scheduler.pauseJob(jobKey);
      return true;
    } catch (SchedulerException e) {
      return false;
    }
  }

  /**
   * 恢复一个定时任务
   * @param name 名称
   * @param group 分组
   * @return 是否删除
   */
  public boolean resumeTask(String name, String group) {
    try {
      JobKey jobKey = JobKey.jobKey(name, group);
      if (!scheduler.checkExists(jobKey)) {
        return false;
      }
      scheduler.resumeJob(jobKey);
      return true;
    } catch (SchedulerException e) {
      return false;
    }
  }

  /**
   * 获取是否存在任务
   * @param name 名称
   * @param group 分组
   * @return true 存在 false 不存在
   */
  public boolean isExistsTask(String name, String group) {
    try {
      JobKey jobKey = JobKey.jobKey(name, group);
      return scheduler.checkExists(jobKey);
    } catch (SchedulerException e) {
      return false;
    }
  }
}
